#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-only
import os
import sys

from scapy.all import (
    TCP, UDP, ICMP, IPv6, ICMPv6EchoRequest, Raw,
    FieldLenField, FieldListField, IntField, IPOption, ShortField,
    get_if_list, sniff, Packet
)
from scapy.layers.inet import _IPOption_HDR

def get_interface(ifname="eth0"):
    """获取指定网络接口（默认eth0）"""
    ifs = get_if_list()
    iface = next((i for i in ifs if ifname in i), None)
    if not iface:
        print(f"Cannot find {ifname} interface")
        sys.exit(1)
    return iface

class IPOption_MRI(IPOption):
    """自定义IP选项（MRI）"""
    name = "MRI"
    option = 31
    fields_desc = [
        _IPOption_HDR,
        FieldLenField("length", None, fmt="B",
                     length_of="swids", adjust=lambda pkt, l: l+4),
        ShortField("count", 0),
        FieldListField("swids", [], IntField("", 0),
                      length_from=lambda pkt: pkt.count*4)
    ]

def handle_packet(pkt):
    """处理IPv4/IPv6数据包"""
    protocol_info = []

    # 检测协议类型
    if pkt.haslayer(ICMP):
        protocol_info.append("ICMPv4")
    elif pkt.haslayer(ICMPv6EchoRequest):
        protocol_info.append("ICMPv6 Echo Request")

    # 检测传输层协议
    if pkt.haslayer(TCP):
        protocol_info.append(f"TCP src:{pkt[TCP].sport} dst:{pkt[TCP].dport}")
    elif pkt.haslayer(UDP):
        protocol_info.append(f"UDP src:{pkt[UDP].sport} dst:{pkt[UDP].dport}")

    # 输出结果
    if protocol_info:
        print("\nGot packet:")
        print(f"  - Protocols: {', '.join(protocol_info)}")
        print(f"  - Summary: {pkt.summary()}")
        if Raw in pkt:
            print(f"  - Payload length: {len(pkt[Raw])} bytes")
        pkt.show2()
        sys.stdout.flush()

def main():
    # 自动选择第一个eth开头的接口
    iface = get_interface()
    print(f"Sniffing on {iface} (IPv4/IPv6)...")

    # BPF过滤器：捕获TCP/UDP/ICMP(IPv4+IPv6)
    bpf_filter = "(tcp or udp or icmp or icmp6) and (port 1234 or port 4321)"

    sniff(
        iface=iface,
        filter=bpf_filter,
        prn=handle_packet,
        store=False
    )

if __name__ == '__main__':
    main()
